#pragma once
#include "TCPServer.hpp"
#include "Util.hpp"
#include <unordered_map>
#include <memory>
#include <sstream>

class HttpMessage
{
public:
    // 向_headers中添加键值对
    bool AddHeader(const std::string &header)
    {
        auto pos = header.find(_HeaderSep);
        if (pos == std::string::npos)
        {
            return false;
        }
        std::string key = header.substr(0, pos);
        std::string value = header.substr(pos + _HeaderSep.size());
        _headers[key] = value;
        return true;
    }
    bool AddHeader(const std::string &key, const std::string &value)
    {
        _headers[key] = value;
        return true;
    }
    void SetData(const std::string &data)
    {
        _data = data;
    }
    const std::string &Data() const
    {
        return _data;
    }
    void SetVersion(const std::string &version)
    {
        _version = version;
    }
    bool Headers(const std::string &key, std::string value)
    {
        if(!_headers.count(key))
            return false;
        value = _headers[key];
        return true;
    }

protected:
    static const std::string _Space;                       // 空格
    static const std::string _LineBreak;                   // 换行符
    static const std::string _BlankLine;                   // 空行
    static const std::string _HeaderSep;                   // 报头分割符
    std::string _version;                                  // Http版本
    std::unordered_map<std::string, std::string> _headers; // 请求/响应报头
    std::string _data;                                     // 请求/响应正文
};
const std::string HttpMessage::_Space = " ";
const std::string HttpMessage::_LineBreak = "\r\n";
const std::string HttpMessage::_BlankLine = "\r\n";
const std::string HttpMessage::_HeaderSep = ": ";

// 请求行: 方法 + 空格 + URI + 空格 + 版本 + 换行符
class HttpRequest : public HttpMessage
{
private:
    void PraseRequestLine(const std::string &request_line)
    {
        std::stringstream buffer(request_line);
        buffer >> _method >> _uri >> _version;
    }
    // 读取报头
    bool GetHead(std::string &request_str)
    {
        static std::string end = _LineBreak + _BlankLine;
        // 判断是否存在一个完整报头
        if (request_str.find(end) == std::string::npos)
        {
            return false;
        }
        // 读取请求行
        std::string request_line;
        Util::ReadLine(request_str, _LineBreak, request_line);
        PraseRequestLine(request_line);
        // 读取请求报头
        std::string header;
        do
        {
            Util::ReadLine(request_str, _LineBreak, header);
            if (header.size() > 0)
            {
                AddHeader(header);
            }
        } while (header.size() > 0); // 读取到空行结束

        // 如果URI包含参数则拆出
        auto pos = _uri.find(_URIArgsSep);
        if (pos != std::string::npos)
        {
            _uri_args = _uri.substr(pos + _URIArgsSep.size());
            _uri = _uri.substr(0, pos);
        }
        return true;
    }

public:
    HttpRequest() {}
    // 序列化
    // std::string Serialize() {}
    // 反序列化
    bool Deserialize(std::string &request_str)
    {
        static bool is_continue = false;
        if (!is_continue)
        {
            if (!GetHead(request_str))
                return false;
        }
        is_continue = true;
        if (_headers.count("Content-Length"))
        {
            int size = std::stoi(_headers["Content-Length"]);
            if (request_str.size() < size)
                return false;
            _data = request_str.substr(0, size);
            request_str.erase(0, size);
        }
        is_continue = false;

        return true;
    }
    const std::string &Uri() const { return _uri; }
    const std::string &Method() const { return _method; }
    ~HttpRequest() {}

private:
    std::string _method;                  // Http请求方法
    std::string _uri;                     // URI
    std::string _uri_args;                // URI中的参数
    static const std::string _URIArgsSep; // URI参数分割符
};
const std::string HttpRequest::_URIArgsSep = "?";

// 状态行: 版本 + 空格 + 状态码 + 空格 + 状态码描述 + 换行符
class HttpResponse : public HttpMessage
{
public:
    HttpResponse()
        : _status(200)
    {
    }
    // 序列化
    std::string Serialize()
    {
        std::string status_line = _version + _Space + std::to_string(_status) + _Space + _StatusDesc[_status] + _LineBreak;
        std::string response_headers;
        for (auto &header : _headers)
        {
            response_headers += header.first + _HeaderSep + header.second + _LineBreak;
        }
        std::string message = status_line + response_headers + _BlankLine + _data;
        return message;
    }
    const std::string &GetMineType(const std::string &extension)
    {
        if (_MineType.count(extension) == 0)
        {
            LOG(LogLevel::ERROR) << "ExtensionToType: 未知的拓展名! [" << extension << "]";
            return _MineType[""];
        }
        return _MineType[extension];
    }
    void SetStatus(int status)
    {
        _status = status;
    }

    // 反序列化
    // bool Deserialize(const std::string request_str) {}
    ~HttpResponse() {}

private:
    int _status;                                                   // 状态码
    static std::unordered_map<int, std::string> _StatusDesc;       // 状态码描述
    static std::unordered_map<std::string, std::string> _MineType; // 后缀转HTTP数据类型
};
std::unordered_map<int, std::string> HttpResponse::_StatusDesc = {
    {200, "OK"},
    {404, "Not Found"},
    {301, "Moved Permanently"},
    {302, "See Other"}};
std::unordered_map<std::string, std::string> HttpResponse::_MineType = {
    {"", "text/plain"},
    {"txt", "text/plain"},
    {"html", "text/html"},
    {"htm", "text/html"},
    {"xml", "text/xml"},
    {"gif", "image/gif"},
    {"jpg", "image/jpeg"},
    {"png", "image/png"}};

class Http
{
private:
    void SetContentLength(HttpResponse &response, const std::string &path)
    {
        size_t filesize = Util::FileSize(path);
        response.AddHeader("Content-Length", std::to_string(filesize));
    }

    void SetContentType(HttpResponse &response, const std::string &path)
    {
        static std::string point = ".";
        auto pos = path.rfind(point);
        std::string extension;
        if (pos == std::string::npos)
        {
            extension = "";
        }
        else
        {
            extension = path.substr(pos + point.size());
        }
        response.AddHeader("Content-Type", response.GetMineType(extension));
    }

    void GetStaticSource(const HttpRequest &request, HttpResponse &response)
    {
        std::string path, data;
        if (request.Uri() == "/")
            path = _HomePage;
        else
            path = _WebRoot + request.Uri();

        if (!Util::ReadFile(path, data))
        {
            response.SetStatus(404);
            LOG(LogLevel::ERROR) << "Http: 获取资源失败! [" << path << "]";
            path = _404Page;
            Util::ReadFile(path, data);
        }
        response.SetData(std::move(data));

        SetContentLength(response, path);
        SetContentType(response, path);
    }

    std::string MakeResponse(HttpRequest &request, HttpResponse &response)
    {
        response.SetVersion(_Version);
        std::string connection;
        if(request.Headers("Connection", connection) && connection == "Keep-alive")
            response.AddHeader("Connection", "Keep-alive");
        std::string uri = request.Uri();
        if (_Redirect.count(uri)) // 重定向
        {
            response.SetStatus(302);
            response.AddHeader("Location", _Redirect[uri]);
        }
        else if (_Route.count(uri)) // uri为微服务
        {
            _Route[uri](request, response);
        }
        else // 获取静态资源
        {
            GetStaticSource(request, response);
        }

        return response.Serialize();
    }

public:
    // TCPServer的回调函数
    void RequestHandler(const std::shared_ptr<TCPConnectSocket> &con_socket)
    {
        std::string cli_message, buffer;
        while (con_socket->Receive(buffer) > 0)
        {
            cli_message += buffer;
            LOG(LogLevel::INFO) << "来自[" << con_socket->addr().Info() << "]的Http请求报文:\n\r" << buffer;
            HttpRequest request;
            if (!request.Deserialize(cli_message))
                continue;
            LOG(LogLevel::DEBUG) << "request 反序列化成功";
            HttpResponse response;
            std::string message = MakeResponse(request, response);

            con_socket->Send(message);
        }
    }

    // 注册重定向
    void RegisterRedirect(const std::string &uri, const std::string &dest)
    {
        _Redirect[uri] = dest;
    }

    // 注册微服务
    using microService_t = std::function<void(const HttpRequest &, HttpResponse &)>;
    void RegisterMicroService(const std::string &uri, microService_t service)
    {
        _Route[uri] = service;
    }

private:
    static const std::string _Version;                             // Http版本
    static const std::string _WebRoot;                             // 网页根目录
    static const std::string _HomePage;                            // 首页
    static const std::string _404Page;                             // 404页面
    std::unordered_map<std::string, std::string> _Redirect; // 临时重定向
    std::unordered_map<std::string, microService_t> _Route; // 微服务路由
};
const std::string Http::_Version = "HTTP/1.1";
const std::string Http::_WebRoot = "/home/shishen/113code/linux-c/Http协议/WebRoot";
const std::string Http::_HomePage = Http::_WebRoot + "/index.html";
const std::string Http::_404Page = Http::_WebRoot + "/404.html";